package org.someone.office;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ooxml.POIXMLDocumentPart.RelationPart;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFCategoryDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFChart;
import org.apache.poi.xslf.usermodel.XSLFPictureShape;
import org.apache.poi.xslf.usermodel.XSLFShape;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xslf.usermodel.XSLFTable;
import org.apache.poi.xslf.usermodel.XSLFTableCell;
import org.apache.poi.xslf.usermodel.XSLFTableRow;
import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
import org.apache.poi.xslf.usermodel.XSLFTextRun;
import org.apache.poi.xslf.usermodel.XSLFTextShape;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTAxDataSource;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTBarChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTBarSer;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTLineChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTLineSer;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumData;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumDataSource;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumRef;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumVal;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTSerTx;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTStrData;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTStrRef;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTStrVal;
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTable;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCell;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableRow;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class PPTUtil {
	
	/**
	 * 复制CTTableCell
	 * @param fromcell
	 * @param tocell
	 * @throws XmlException
	 */
	public static void copyTableCell(CTTableCell fromcell, CTTableCell tocell) throws XmlException{
		for(CTTextParagraph paragraph: fromcell.getTxBody().getPList()){
			CTTextParagraph newparagraph = tocell.getTxBody().addNewP();
			newparagraph.set(CTTextParagraph.Factory.parse(paragraph.xmlText()));
			copyTextParagraph(paragraph, newparagraph);
		}
	}
	
	/**
	 * 复制CTTextParagraph
	 * @param fromparagraph
	 * @param toparagraph
	 * @throws XmlException
	 */
	public static void copyTextParagraph(CTTextParagraph fromparagraph, CTTextParagraph toparagraph) throws XmlException{
		for(CTRegularTextRun run : fromparagraph.getRList()){
			CTRegularTextRun newrun = toparagraph.addNewR();
			newrun.set(CTRegularTextRun.Factory.parse(run.xmlText()));
			newrun.setT(run.getT());
		}
	}
	
	/**
	 * 复制tables行
	 * @param xslftable
	 * @param row
	 * @param length
	 * @param pos
	 * @throws XmlException 
	 */
	public static void copyTableRow(XSLFTable xslftable, XSLFTableRow row, int length, int pos) throws XmlException{
		for(int i=0; i< length; i++){
			//样式中添加行
			CTTableRow newrow = xslftable.getCTTable().insertNewTr(pos);
			CTTableRow newrowtemplate = CTTableRow.Factory.parse(row.getXmlObject().xmlText());
			newrow.set(newrowtemplate);
			for(CTTableCell cell : row.getXmlObject().getTcList()){
				CTTableCell newcell = newrow.addNewTc();
				newcell.set(CTTableCell.Factory.parse(cell.xmlText()));
				newcell.addNewTxBody();
				copyTableCell(cell, newcell);
			}
		}
	}
	
	
	/**
	 * 是否是table中循环的行
	 * @param cttablerow
	 * @return
	 */
	public static boolean isLoopline(CTTableRow cttablerow){
		for(CTTableCell cell:cttablerow.getTcList()){
			if(cell.getTxBody() == null) continue;
			for(CTTextParagraph paragraph:cell.getTxBody().getPList()){
				for(CTRegularTextRun run: paragraph.getRList()){
	            	String ptext = run.getT();
	            	if(VarUtil.isVar(ptext, VarUtil.defaultRegex)){
		                return true;
		            }
				}
			}
		}
		return false;
	}
	
	/**
	 * 是否是table中循环的行
	 * @param xslftablerow
	 * @return
	 */
	public static boolean isLoopline(XSLFTableRow xslftablerow){
		List<XSLFTableCell> tablecellslist = xslftablerow.getCells();
		for(XSLFTableCell cell: tablecellslist){
			List<XSLFTextParagraph> tpslist = cell.getTextParagraphs();
			for(XSLFTextParagraph paragraph : tpslist){
				String ptext = paragraph.getText();
	            if(VarUtil.isVar(ptext, VarUtil.defaultRegex)){
	                return true;
	            }
	            for(CTRegularTextRun run: paragraph.getXmlObject().getRList()){
	            	ptext = run.getT();
	            	if(VarUtil.isVar(ptext, VarUtil.defaultRegex)){
		                return true;
		            }
				}
			}
		}
		return false;
	}
	
	/**
	 * 替换循环变量的tables
	 * @param xslftable
	 * @param paramap
	 * @throws XmlException 
	 */
	public static void replaceTableLoop(XSLFTable xslftable, Map<String, Object> paramap) throws XmlException{
		
		String strcontent = xslftable.getCell(0, 0).getText();
	    String strval = VarUtil.getVar(strcontent, VarUtil.defaultRegex);
	    if(strval != null){
		    strval = strval.substring(2,strval.length()-1);
	        Object obj = paramap.get(strval);
	        if(obj!=null && obj instanceof List){
		        //将第一行、第一列单元格中标识为循环table的变量删除
	        	Map<String,Object> tmpMap = new HashMap<String,Object>();
		        tmpMap.put(strval,"");
		        replaceTableCell(xslftable.getCell(0, 0), tmpMap);
		        List<Map<String,Object>> mapList = (List<Map<String,Object>>)obj;
		        if(mapList!=null && mapList.size()>0){
		        	int indextr = 0;
		        	boolean isLoop = false;
		        	for(XSLFTableRow row : xslftable.getRows()){
		        		if(isLoopline(row)){
		        			copyTableRow(xslftable, row, mapList.size()-1, indextr);
		        			isLoop = true;
		        			break;
		        		}
		        		indextr++;
		        	}
		            if(isLoop) {
		            	CTTable table = xslftable.getCTTable();
		            	for (int i = 0; i < mapList.size(); i++) {
	                        Map<String, Object> varMap = mapList.get(i);
	                        for(CTTableRow row : table.getTrList()){
	                        	if(isLoopline(row)){
	                        		replaceCTTableRow(row, varMap);
	                        		break;
	                        	}
			            	}
		            	}
		            }
		            
		        }
	        }
	    }
	}
	
	/**
	 * 替换图表
	 * @param xslfchart		图表
	 * @param paramap		变量库
	 * @throws InvalidFormatException
	 * @throws IOException
	 */
	public static void replaceChart(XSLFChart xslfchart, Map<String, Object> paramap) throws InvalidFormatException, IOException{
		XSSFWorkbook workbook = xslfchart.getWorkbook();
		XSSFSheet sheet = workbook.getSheetAt(0);
		ExcelUtil.replaceSheet(sheet, paramap);
	    ExcelUtil.replaceSheet4Loop(sheet, paramap, false);
	    ExcelUtil.parseStr2Db4Sheet(sheet);
	    if(xslfchart!=null){
	    	if(xslfchart.getCTChart()!=null){
	    		CTChartUtil.reloadCTChart(xslfchart.getCTChart(), sheet);
	    	}
	    }
	}

	/**
	 * 根据表格内容替换chart默认值中的数据
	 * @param cd
	 * @param sheet
	 */
	public static void replaceChartData(XDDFChartData cd,XSSFSheet sheet){
		int icol = 1;
		for(XDDFChartData.Series series : cd.getSeries()){
			XDDFCategoryDataSource category = null;
			XDDFNumericalDataSource<Double> values = null;
			int firstRow = 1;
			int lastRow = sheet.getLastRowNum();
			CellRangeAddress cregion = new CellRangeAddress(firstRow,lastRow,0,0);
			category = XDDFDataSourcesFactory.fromStringCellRange(sheet, cregion);
			CellRangeAddress vregion = new CellRangeAddress(firstRow,lastRow,icol,icol);
			ExcelUtil.parseStr2Db4Range(sheet, vregion);
			values = XDDFDataSourcesFactory.fromNumericCellRange(sheet, vregion); 
			series.replaceData(category, values);
			series.plot();
			icol++;
		}
	}
	
	/**
	 * 替换pptx中的全部图表
	 * @param chartslist	图表list
	 * @param paramap		变量库
	 * @throws InvalidFormatException
	 * @throws IOException
	 */
	public static void replaceChartsList(List<POIXMLDocumentPart> chartslist, Map<String, Object> paramap) throws InvalidFormatException, IOException{
		for(POIXMLDocumentPart part : chartslist){
			if(part instanceof XSLFChart){
				replaceChart((XSLFChart) part, paramap);
			}
		}
	}
	
	/**
	 * 替换CTRun
	 * @param run
	 * @param paramap
	 */
	public static void replaceCTRun(CTRegularTextRun run, Map<String, Object> paramap){
		String ptext = run.getT();
		ptext = VarUtil.replaceText(ptext, paramap);
		run.setT(ptext);
	}
	
	/**
	 * 替换CTRun list
	 * @param runlist
	 * @param paramap
	 */
	public static void replaceCTRunsList(List<CTRegularTextRun> runlist, Map<String, Object> paramap){
		for(CTRegularTextRun run:runlist){
			replaceCTRun(run, paramap);
		}
	}
	
	/**
	 * 替换CTTextParagraph
	 * @param paragraph
	 * @param paramap
	 */
	public static void replaceCTParagraph(CTTextParagraph paragraph, Map<String, Object> paramap){
		replaceCTRunsList(paragraph.getRList(), paramap);
	}
	
	/**
	 * 替换CTTextParagraph list
	 * @param paragraphlist
	 * @param paramap
	 */
	public static void replaceCTParagraphsList(List<CTTextParagraph> paragraphlist, Map<String, Object> paramap){
		for(CTTextParagraph paragraph:paragraphlist){
			replaceCTParagraph(paragraph, paramap);
		}
	}
	
	/**
	 * 替换CTTableCell 
	 * @param cell
	 * @param paramap
	 */
	public static void replaceCTTableCell(CTTableCell cell, Map<String, Object> paramap){
		if(cell.getTxBody() != null){
			replaceCTParagraphsList(cell.getTxBody().getPList(), paramap);
		}
	}
	
	/**
	 * 替换CTTableCell list
	 * @param celllist
	 * @param paramap
	 */
	public static void replaceCTTableCellsList(List<CTTableCell> celllist, Map<String, Object> paramap){
		for(CTTableCell cell:celllist){
			replaceCTTableCell(cell, paramap);
		}
	}
	
	/**
	 * 替换CTTableRow
	 * @param row
	 * @param paramap
	 */
	public static void replaceCTTableRow(CTTableRow row, Map<String, Object> paramap){
		replaceCTTableCellsList(row.getTcList(), paramap);
	}
	
	/**
	 * 替换CTTableRow list
	 * @param rowlist
	 * @param paramap
	 */
	public static void replaceCTTableRowsList(List<CTTableRow> rowlist, Map<String, Object> paramap){
		for(CTTableRow row:rowlist){
			replaceCTTableRow(row, paramap);
		}
	}
	
	/**
	 * 替换CTTable
	 * @param table
	 * @param paramap
	 */
	public static void repalceCTTable(CTTable table, Map<String, Object> paramap){
		replaceCTTableRowsList(table.getTrList(), paramap);
	}
	
	/**
	 * 替换段落
	 * @param paragraph	段落
	 * @param paramap	变量库
	 */
	public static void replaceParagraph(XSLFTextParagraph paragraph, Map<String,Object> paramap){
		replaceRunsList(paragraph.getTextRuns(), paramap);
	}

	/**
	 * 替换多个段落
	 * @param paragraphlist	段落list 
	 * @param paramap		变量库
	 */
	public static void replaceParagraphsList(List<XSLFTextParagraph> paragraphlist, Map<String,Object> paramap){
		for(XSLFTextParagraph paragraph: paragraphlist){
			replaceParagraph(paragraph, paramap);
		}
	}

	/**
	 * 替换pptx
	 * @param is		模板文件流
	 * @param paramap	变量库
	 * @return			pptx 对象
	 * @throws IOException
	 * @throws InvalidFormatException
	 * @throws XmlException 
	 */
	public static XMLSlideShow replacePptx(InputStream is, Map<String, Object> paramap) throws IOException, InvalidFormatException, XmlException {
		XMLSlideShow pptx = new XMLSlideShow(is);
		replaceSlidesList(pptx.getSlides(), paramap);
		return pptx;
	}

	/**
	 * 替换pptx
	 * @param is		输入流
	 * @param os		输出流
	 * @param paramap	变量库
	 * @throws InvalidFormatException
	 * @throws IOException
	 * @throws XmlException 
	 */
	public static void replacePptx2IO(InputStream is, OutputStream os, Map<String, Object> paramap) throws InvalidFormatException, IOException, XmlException{
		XMLSlideShow pptx = replacePptx(is, paramap);
		pptx.write(os);
		pptx.close();
	}

	/**
	 * 替换run
	 * @param run		run
	 * @param paramap	变量库
	 */
	public static void replaceRun(XSLFTextRun run, Map<String,Object> paramap){
		String ptext = run.getRawText();
		ptext = VarUtil.replaceText(ptext, paramap);
		run.setText(ptext);
	}

	/**
	 * 替换runlist
	 * @param runlist	runlist
	 * @param paramap	变量库
	 */
	public static void replaceRunsList(List<XSLFTextRun> runlist, Map<String,Object> paramap){
		for(XSLFTextRun run : runlist){
			replaceRun(run, paramap);
		}
	}

	/**
	 * 替换某一页中的除图表外的内容
	 * @param shapeslist	形状
	 * @param paramap		变量库
	 * @throws XmlException 
	 * @throws IOException 
	 */
	public static void replaceShapesList(List<XSLFShape> shapeslist, Map<String, Object> paramap) throws XmlException, IOException{
		for(XSLFShape xslfshape: shapeslist){
			if(xslfshape instanceof XSLFTextShape){
				replaceParagraphsList(((XSLFTextShape) xslfshape).getTextParagraphs(), paramap);
			}
			if(xslfshape instanceof XSLFTable){
				replaceTable((XSLFTable) xslfshape, paramap);
				replaceTableLoop((XSLFTable) xslfshape, paramap);
			}
			if(xslfshape instanceof XSLFPictureShape){
//				System.out.println(xslfshape.getShapeName());
//				System.out.println(((XSLFPictureShape) xslfshape).getPictureData().getFileName());
				Object objpic = paramap.get(xslfshape.getShapeName());
				if(objpic instanceof byte[]){
					((XSLFPictureShape) xslfshape).getPictureData().setData((byte[])objpic);
				}
			}
		}
	}

	/**
	 * 替换某一页PPTX
	 * @param xslfslide		单页pptx
	 * @param paramap		变量库
	 * @throws InvalidFormatException
	 * @throws IOException
	 * @throws XmlException 
	 */
	public static void replaceSlide(XSLFSlide xslfslide, Map<String, Object> paramap) throws InvalidFormatException, IOException, XmlException{
		replaceChartsList(xslfslide.getRelations(), paramap);
		replaceShapesList(xslfslide.getShapes(), paramap);
	}

	/**
	 * 替换所有pptx页
	 * @param xslfslideslist	页list
	 * @param paramap			变量库
	 * @throws InvalidFormatException
	 * @throws IOException
	 * @throws XmlException 
	 */
	public static void replaceSlidesList(List<XSLFSlide> xslfslideslist, Map<String, Object> paramap) throws InvalidFormatException, IOException, XmlException{
		for(XSLFSlide xslfslide : xslfslideslist){
			replaceSlide(xslfslide, paramap);
		}
	}

	/**
	 * 替换表格
	 * @param xslftable	表格
	 * @param paramap	变量库
	 */
	public static void replaceTable(XSLFTable xslftable, Map<String, Object> paramap){
		replaceTableRowsList(xslftable.getRows(), paramap);
	}

	/**
	 * 替换表格中的某个单元格
	 * @param tablecell		单元格
	 * @param paramap		变量库
	 */
	public static void replaceTableCell(XSLFTableCell tablecell, Map<String, Object> paramap){
		replaceParagraphsList(tablecell.getTextParagraphs(), paramap);
	}
	
	/**
	 * 替换表格中的多个单元格
	 * @param tablecelllist	单元格list 
	 * @param paramap		变量库
	 */
	public static void replaceTableCellsList(List<XSLFTableCell> tablecelllist, Map<String, Object> paramap){
		for(XSLFTableCell cell : tablecelllist){
			replaceTableCell(cell, paramap);
		}
	}
	
	/**
	 * 替换表格中某一行
	 * @param xslftablerow	表格行
	 * @param paramap		变量库
	 */
	public static void replaceTableRow(XSLFTableRow xslftablerow, Map<String, Object> paramap){
		replaceTableCellsList(xslftablerow.getCells(), paramap);
	}
	
	/**
	 * 替换表格中某些行
	 * @param tablerowslist	表格行list
	 * @param paramap		变量库
	 */
	public static void replaceTableRowsList(List<XSLFTableRow> tablerowslist, Map<String, Object> paramap){
		for(XSLFTableRow row: tablerowslist){
			replaceTableRow(row, paramap);
		}
	}
	
	
	
	
	
	
}
